#include "axl_config.h"
#include "axl_animations.h"

using namespace std;
using namespace AXL_Projects;
#if (USE_OPENLAYER==1)
	using namespace ol;
#endif

//
/* animation library (storage for items that are available, usually read from XML file
   game animations contains an actual object representing an animation so that it can be tracked for each sprite
*/

/*  a library contains a list of library animations, key is the animation name, but can use iterators to loop
	a library animation contains a sequence of frames (or one frame required)
	a library animation frame contains the details of a single frame (bitmap, time to display on screen)
*/

//forward decl1arations
class AXL_Projects::AnimationLibrary;
struct AXL_Projects::AnimationLibraryFrame;
class AXL_Projects::AnimationLibraryFrames;

//statics
//	frame
map<string,AXL_BITMAP*> AnimationLibrary::StoredBitmaps;
//	library (default for each frames - global default)
LoopType AnimationLibrary::DefaultLoop=LOOP_ONCE;
int  AnimationLibrary::DefaultMilliSecondWait=-1;
int  AnimationLibrary::DefaultFrameWait=-1;
int  AnimationLibrary::DefaultColourDepth=32;
bool AnimationLibrary::DefaultAutoMove=true;
int  AnimationLibrary::DefaultSheetWidth=64;
int  AnimationLibrary::DefaultSheetHeight=64;
bool AnimationLibrary::DefaultSheetGrid=false;
bool AnimationLibrary::DefaultIsASheetGraphic=false;
bool AnimationLibrary::DefaultHasPPCOLMask=false;

#if (USE_OPENLAYER!=1)
BitmapType AnimationLibrary::DefaultTypeOfBitmap=TYPE_MEMORY;
#else
BitmapType AnimationLibrary::DefaultTypeOfBitmap=TYPE_VIDEO;
#endif

BitmapType AnimationLibrary::MaxTypeOfBitmap=TYPE_VIDEO;	//default is to allow any type, i.e. do what code asks
Animation::Animation(AnimationLibrary* const al, AnimationLibraryFrames* const af)
{
	AnimationSequence=af;
	Initialise(al);
}
Animation::Animation(AnimationLibrary* const al, const string& item)
{
	assert(al);
	if(al!=NULL)
		AnimationSequence=al->GetAnimation(item);

	assert(AnimationSequence);
	Initialise(al);
}

Animation::~Animation()
{
#if (USE_OPENLAYER!=1)
	if(FadingSpriteBMP!=NULL) destroy_bitmap( FadingSpriteBMP );
#else
	if(FadingSpriteBMP!=NULL) 
	{
		FadingSpriteBMP->Destroy();
		delete FadingSpriteBMP;
	}
#endif
	FadingSpriteBMP=NULL;
}

void Animation::Initialise(AnimationLibrary* const al) 
{
	//trap errors hopefully during development
	assert(al!=NULL && AnimationSequence!=NULL);

	Library=al;
	ReadOnly_CurrentItem=NULL;
	ReadOnly_CurrentPPCOLMask=NULL;
#if (USE_OPENLAYER==1)
	ReadOnly_CurrentCollisionPoly=NULL;
#endif
	Paused=false;
	ReadOnly_EndReached=false;
	ReverseOnceToggle=false;
	FrameCountOverride=-1;
	GoingForward=true;

	FadingSpriteIn=FadingSpriteOut=false;
	FadingStepInc=0.0;
	ReadOnly_TimersCounter[0]=255;
	FadingSpriteBMP=NULL;
	FadingColour=0;	//black

	//countdown timers are only false when the timer is invoked and not finished
	//beware if using them without knowing if they have been invoked or not
	for(int i=1;i<MAX_COUNTDOWN_TIMERS;i++)
	{
		ReadOnly_Timers[i]=true;
		ReadOnly_TimersCounter[i]=0;
	}

	//set initial graphic
	if(al==NULL || AnimationSequence==NULL)
	{

		AnimationLibrary::SetGlobalErrorString("animation or library not loaded");
		return;
	}

	this->AnimationSequence->Loop=this->AnimationSequence->OriginalLoop;
	this->AnimationSequence->AutoMove=this->AnimationSequence->OriginalAutoMove;
	AnimationIterator=AnimationSequence->FrameItems.begin();
	CurrentFrameItem=(*AnimationIterator)->FWait;
#if (USE_OPENLAYER!=1)
			ReadOnly_CurrentPPCOLMask=(*AnimationIterator)->PPCOLMask;
#else
			ReadOnly_CurrentCollisionPoly=(*AnimationIterator)->FrameCollisionPoly;
#endif

	ReadOnly_CurrentItem=(*AnimationIterator)->Image;
	if(ReadOnly_CurrentItem) ReadOnly_TypeOfBitmap=(*AnimationIterator)->TypeOfBitmap;
	this->ColourDepth=AnimationSequence->DefaultColourDepth;
	this->GetStandardDimensions(&w,&h);

	switch(ColourDepth)
	{
	case 8:
		this->MaskColour=0;
		break;
	default:
		MaskColour=makecol(255,0,255);
		break;
	}
}

void Animation::SetNewLoopType(const LoopType lt)
{
	this->Reset();
	this->AnimationSequence->Loop=lt;
}

void Animation::Reset() 
{ 
	Initialise(Library);
	//this->AnimationSequence->Loop=this->AnimationSequence->OriginalLoop;
}

void Animation::SetAutoMode(bool am)
{
	this->AnimationSequence->AutoMove=am;
}
bool Animation::GetAutoMode() const
{
	return this->AnimationSequence->AutoMove;
}
bool Animation::SetNewAnimation(const string& id)
{
	assert(id!="");
	AnimationLibraryFrames* found;
	found=Library->GetAnimation(id);
	if(found==NULL) return false;	//keep old data
	else
	{
		this->AnimationSequence=found;
		Initialise(this->Library);
		return true;
	}
}

bool Animation::SetNewAnimation(AnimationLibraryFrames* const af)
{
	assert(af);
	this->AnimationSequence=af;
	Initialise(this->Library);
	return true;
}
#if (OPTIMISE_NOFADE==0)
void Animation::FadeIn(int ms,bool alterbmp,int colour, int startinglevel)
{
	//fade to solid
	assert(ms>0);
	if(FadingSpriteIn) return;
	this->FadingModifyBitmap=alterbmp;

	this->FadingSpriteIn=true;
	this->FadingSpriteOut=false;
	float framesreq=this->Library->fps*(ms/1000);
	this->FadingStepInc=256/framesreq;

	if(startinglevel!=-1) this->ReadOnly_TimersCounter[0]=startinglevel;
	FadingColour=colour;
	if(FadingStepInc<=0.0) FadingStepInc=1.0;
	//all animations should be the same size
	if(FadingSpriteBMP==NULL && alterbmp) 
	{
#if (USE_OPENLAYER!=1)
		if(is_video_bitmap(this->ReadOnly_CurrentItem))
			FadingSpriteBMP=create_video_bitmap(w,h);
		else if(is_system_bitmap(this->ReadOnly_CurrentItem))
			FadingSpriteBMP=create_system_bitmap(w,h);
		else
		FadingSpriteBMP=create_bitmap(w,h);
#else
		FadingSpriteBMP=new Bitmap(w,h,Rgba::INVISIBLE);
#endif
	}
	ReadOnly_Timers[0]=false;
}
#endif

#if( OPTIMISE_NOFADE==0)
void Animation::FadeOut(int ms, bool alterbmp,int colour, int startinglevel)
{
	//fade to empty
	assert(ms>0);
	if(FadingSpriteOut) return;

	this->FadingModifyBitmap=alterbmp;
	this->FadingSpriteOut=true;
	FadingSpriteIn=false;
	float framesreq=this->Library->fps*(ms/1000);
	this->FadingStepInc=-(256/framesreq);

	if(startinglevel!=-1) this->ReadOnly_TimersCounter[0]=startinglevel;
	if(FadingStepInc==0.0) FadingStepInc=-1.0;
	FadingColour=colour;

	//all animations should be the same size
	if(FadingSpriteBMP==NULL && alterbmp) 
	{
#if (USE_OPENLAYER!=1)
		if(is_video_bitmap(this->ReadOnly_CurrentItem))
			FadingSpriteBMP=create_video_bitmap(w,h);
		else if(is_system_bitmap(this->ReadOnly_CurrentItem))
			FadingSpriteBMP=create_system_bitmap(w,h);
		else
			FadingSpriteBMP=create_bitmap(w,h);
#else
		FadingSpriteBMP=new Bitmap(w,h,Rgba::INVISIBLE);
#endif
	}

	ReadOnly_Timers[0]=false;
}
#endif


#if(OPTIMISE_NOCOUNTERS==0)
void Animation::SetCustomCountDown(int timer, int milliseconds)
{
	assert(timer>0 && timer<MAX_COUNTDOWN_TIMERS && milliseconds>0);
	//1 - MAX_COUNTDOWN_TIMERS-1 only (0 is the fade timer)
	if(timer>0 && timer<MAX_COUNTDOWN_TIMERS && milliseconds>0 )
	{
		//countdown is the number of frames before the end
		ReadOnly_TimersCounter[timer]=this->Library->fps*(milliseconds/1000);
		ReadOnly_Timers[timer]=false;
	}
}
#endif

#if (OPTIMISE_NOFADE==0) || (OPTIMISE_NOCOUNTERS==0)
void Animation::ManualTimerUpdate()
{
	//need to only update timers and fade stuff when manual mode every frame
	//when in manual mode call this every frame and when need to step do not call this but instead
	//call NextMove() that does the correct stuff
	TimerUpdate();
	ManualTimerUpdateHelperBitmap();	
	ManualTimerUpdateHelperFade();
}
#endif

#if (OPTIMISE_NOFADE==0) || (OPTIMISE_NOCOUNTERS==0)
inline void Animation::TimerUpdate()
{
#if (OPTIMISE_NOFADE==0)
	if(FadingSpriteOut || FadingSpriteIn)
	{
		ReadOnly_TimersCounter[0]+=FadingStepInc;
		if(ReadOnly_TimersCounter[0]<0.0) 
		{
			ReadOnly_TimersCounter[0]=0.0;
			ReadOnly_Timers[0]=true;
			//do not reset fade as if 0 then stay there until a reset or a starting fade
		//	FadingSpriteIn=FadingSpriteOut=false;
		}
		else
		{
			if(ReadOnly_TimersCounter[0]>255)
			{
				//once fully visible then no need to set fade
				ReadOnly_TimersCounter[0]=255.0;
				FadingSpriteIn=FadingSpriteOut=false;
				ReadOnly_CurrentItem=(*AnimationIterator)->Image;		//for single bitmaps, need to redraw
				if(ReadOnly_CurrentItem) ReadOnly_TypeOfBitmap=(*AnimationIterator)->TypeOfBitmap;
				ReadOnly_CurrentPPCOLMask=(*AnimationIterator)->PPCOLMask;
#if (USE_OPENLAYER==1)
				ReadOnly_CurrentCollisionPoly=(*AnimationIterator)->FrameCollisionPoly;
#endif
				ReadOnly_Timers[0]=true;
			}
		}
#if (USE_OPENLAYER!=1)
		if(this->FadingModifyBitmap) clear_to_color(FadingSpriteBMP,this->MaskColour);
#else
		if(this->FadingModifyBitmap)
		{
			Canvas::SetTo(*FadingSpriteBMP);
			Canvas::Fill(Rgba::INVISIBLE);
			Canvas::SetTo(SCREEN_BACKBUF);
		}
#endif
	}
#endif

#if (OPTIMISE_NOCOUNTERS==0)
	//countdown - don't use 0 (Fade timer) as that is dealt with above
	for(int i=1;i<MAX_COUNTDOWN_TIMERS;i++)
	{
		if(ReadOnly_Timers[i]==false)
		{
			//flag is false so the timer has been started. true means counter is reached zero or has not started
			if(ReadOnly_TimersCounter[i]<=0)
			{
				ReadOnly_TimersCounter[i]=0;
				ReadOnly_Timers[i]=true;
			}
			else
			{
				ReadOnly_TimersCounter[i]--;
			}
		}
	}
#endif
	
}
#endif

void Animation::NextMove()
{
	//this should be called every frame, it decrements the current frame count and changes frames if required
	//framecount has already been set via the library or the set new speed
	//if in manual mode, then call when needed. However need to call TimerUpdate() every frame if using timers

	
	if(Paused)
		return;

	TimerUpdate();
#if (OPTIMISE_NOFADE==0) 
	if(FadingSpriteOut || FadingSpriteIn)
	{
		//if not fading check if need to abort
		if(AnimationSequence->FrameItems.size()<=1)
			return;

		if(ReadOnly_EndReached)
			return;
	}
#else
		//if fade optimised out then check to abort
		if(AnimationSequence->FrameItems.size()<=1)
			return;

		if(ReadOnly_EndReached)
			return;
#endif

	//if manual then we want it to do it straight away as counts are not used
	bool DoNext=!AnimationSequence->AutoMove;

	CurrentFrameItem--;
	//only show if valid and there are frames to show
	if(( CurrentFrameItem<1 || DoNext) && AnimationSequence->FrameItems.size()>1)
	{
		//reset framecount
		if(FrameCountOverride==-1) 
			CurrentFrameItem=(*AnimationIterator)->FWait;
		else 
			CurrentFrameItem=FrameCountOverride;
			//CurrentFrameItem=60;
		//get new loop

		//end is one past the last one
		//begin is the first one
		if(GoingForward) 
		{
			AnimationIterator++;
			if(AnimationIterator==AnimationSequence->FrameItems.end())
			{
				//set iterator based on the loop
				switch(AnimationSequence->Loop)
				{
				case LOOP_START:
					//go to start
					AnimationIterator=AnimationSequence->FrameItems.begin();
					break;
				case LOOP_REVERSEREPEAT:
				case LOOP_REVERSEONCE:
					//go back to the previous one, so need to go back two
					AnimationIterator--;	//last one
					//just in case there is only one frame
					if(AnimationIterator!=AnimationSequence->FrameItems.begin()) AnimationIterator--;
					GoingForward=false;		//backward
					break;
				case LOOP_REVERSEBACK:
					if(ReverseOnceToggle) 
						ReadOnly_EndReached=true;	//been once around so end
					AnimationIterator--;	//last one
					GoingForward=false;		//backward
					break;
				case LOOP_ONCE:
					AnimationIterator--;	//stay still
					ReadOnly_EndReached=true;
					break;
				case LOOP_INVALID:
					//nothing done
					break;
				}
			}
		}
		else
		{
			if(AnimationIterator==AnimationSequence->FrameItems.begin())
			{
				switch(AnimationSequence->Loop)
				{
					//loop_start never reached here as its a forward only thing
					// however can be set by user so default to stop
				case LOOP_REVERSEREPEAT:
					GoingForward=true;
					AnimationIterator++;
					break;
				case LOOP_REVERSEONCE:
					ReadOnly_EndReached=true;	//at the start so it is the end
					break;
				case LOOP_REVERSEBACK:
					ReverseOnceToggle=true;
					GoingForward=true;
					AnimationIterator++;
					break;
				default:
					ReadOnly_EndReached=true;
					break;
				}
			}
			else
				AnimationIterator--;
		}
		//time for a new graphic
		assert(*AnimationIterator);
		if(!ReadOnly_EndReached)
		{
			ReadOnly_CurrentItem=(*AnimationIterator)->Image;
   			ReadOnly_TypeOfBitmap=(*AnimationIterator)->TypeOfBitmap;
#if (USE_OPENLAYER!=1)
			ReadOnly_CurrentPPCOLMask=(*AnimationIterator)->PPCOLMask;
#else
			ReadOnly_CurrentCollisionPoly=(*AnimationIterator)->FrameCollisionPoly;
#endif
		}
	}
	else
	{
		ManualTimerUpdateHelperBitmap();
	}
	ManualTimerUpdateHelperFade();
}

inline void Animation::ManualTimerUpdateHelperBitmap()
{
	//pointer is changed when fading so reset back to image between animations
	if(this->FadingModifyBitmap && (FadingSpriteOut || FadingSpriteIn ))
	{
		ReadOnly_CurrentItem=(*AnimationIterator)->Image;
		ReadOnly_TypeOfBitmap=(*AnimationIterator)->TypeOfBitmap;
	}
}

void Animation::ManualTimerUpdateHelperFade()
{

#if (OPTIMISE_NOFADE==0)
	if(this->FadingModifyBitmap && (FadingSpriteOut || FadingSpriteIn ))
	{
#if (USE_OPENLAYER==1)
		Canvas::SetTo(*FadingSpriteBMP);
		ReadOnly_CurrentItem->Blit(0,0,(1.0/256.0)*ReadOnly_TimersCounter[0]);
		//Canvas::Fill(Rgba(0,0,0,(int)ReadOnly_TimersCounter[0]), ALPHA_ONLY);
		Canvas::SetTo(SCREEN_BACKBUF);
#else
#if(USE_FBLEND==1)
		int FadeColour;
		acquire_bitmap(FadingSpriteBMP);
		fblend_fade_to_color(ReadOnly_CurrentItem, FadingSpriteBMP, 0,0, FadingColour, (int)ReadOnly_TimersCounter[0]);
		//need to restore the magic pink/index 0 colour
		if(this->ColourDepth==32)
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel32(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_32)
					{
						_putpixel32(FadingSpriteBMP,i,j,MASK_COLOR_32);
					}
				}
			}
		} else if(this->ColourDepth==16)
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel16(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_16)
					{
						acquire_bitmap(FadingSpriteBMP);
						_putpixel(FadingSpriteBMP,i,j,MASK_COLOR_8);
						release_bitmap(FadingSpriteBMP);
					}
				}
			}
		} else if(this->ColourDepth==8)
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_8)
					{
						acquire_bitmap(FadingSpriteBMP);
						_putpixel(FadingSpriteBMP,i,j,MASK_COLOR_8);
						release_bitmap(FadingSpriteBMP);
					}
				}
			}
		} else if(this->ColourDepth==15)
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel15(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_15)
					{
						acquire_bitmap(FadingSpriteBMP);
						_putpixel15(FadingSpriteBMP,i,j,MASK_COLOR_15);
						release_bitmap(FadingSpriteBMP);
					}
				}
			}
		} else if(this->ColourDepth==24)
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel24(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_24)
					{
						acquire_bitmap(FadingSpriteBMP);
						_putpixel24(FadingSpriteBMP,i,j,MASK_COLOR_24);
						release_bitmap(FadingSpriteBMP);
					}
				}
			}
		} else	//assume 32
		{
			for(int i=0;i<w;i++)
			{
				for(int j=0;j<w;j++)
				{
					FadeColour=_getpixel32(ReadOnly_CurrentItem, i, j);
					if(FadeColour==MASK_COLOR_32)
					{
						acquire_bitmap(FadingSpriteBMP);
						_putpixel32(FadingSpriteBMP,i,j,MASK_COLOR_32);
						release_bitmap(FadingSpriteBMP);
					}
				}
			}
		}
						release_bitmap(FadingSpriteBMP);
#else
		clear_to_color(FadingSpriteBMP,FadingColour);
		set_trans_blender(0,0,0, (int)ReadOnly_TimersCounter[0]);
		draw_trans_sprite(FadingSpriteBMP,ReadOnly_CurrentItem, 0,0);
#endif
#endif
		ReadOnly_CurrentItem=FadingSpriteBMP;
	}
#endif
}

void Animation::Pause() { Paused=true;}
void Animation::Resume() { Paused=false;}
void Animation::SetNewSpeedFrameCount(int fc) 
{
	if(fc>=0)
		FrameCountOverride=fc;
}
void Animation::SetNewSpeedMS(int ms) 
{ 
	if(ms==0) FrameCountOverride=0;
	else if(ms>=0) 
		FrameCountOverride=(this->Library->fps*ms)/1000;
}
void Animation::GetStandardDimensions(int* width, int* height) const
{
	if(ReadOnly_CurrentItem!=NULL)
	{
#if (USE_OPENLAYER!=1)
		*width=ReadOnly_CurrentItem->w;
		*height=ReadOnly_CurrentItem->h;
#else
		*width=ReadOnly_CurrentItem->Width();
		*height=ReadOnly_CurrentItem->Height();
#endif
	}
}
int Animation::GetCurrentSpeedMS() const
{
	if(this->FrameCountOverride==-1) return (*AnimationIterator)->MSWait;
	else return this->FrameCountOverride*(1000/Library->fps);
}

int Animation::GetCurrentSpeedFrameCount() const
{
	if(this->FrameCountOverride==-1) return (*AnimationIterator)->FWait;
	else return this->FrameCountOverride;
}

#if (USE_OPENLAYER==1)
int Animation::CheckCollision(int this_x, int this_y, Poly* mask1, int mask1_x, int mask1_y) const
{
	//if( !check_bb_collision_general(this_x,this_y,w,h,mask1_x,mask1_y,mask1->w,mask1->h) ) //If there is not bounding box collision...
	//	return 0;

	//bounding box found, try for a closer match	
    if(ReadOnly_CurrentCollisionPoly==NULL || mask1==NULL) 
			return 0;
	else
	{
	    if(ReadOnly_CurrentCollisionPoly->Collides((Poly)*mask1,Placement(Vec2D(this_x,this_y)),Placement(Vec2D(mask1_x,mask1_y))))
			return 2;
		else
			return 0;    
	}
}
#else
int Animation::CheckCollision(int this_x, int this_y, PPCOL_MASK *mask1, int mask1_x, int mask1_y) const
{
	//this_x and this_y are the positions of this animation, the remainder are the animation being checked
	//this is best probably in a sprite class
 int dx1, dx2, dy1, dy2; //We will use this deltas...
 int py; //This will store the Y position...
 int maxh; //This will store the maximum height...

 int chunkm1, chunkm2; //This will store the number of the current chunk in the masks...
 int chunkm1p, chunkm2p; //This will store the position in the current chunk of the masks...

 if(!mask1 || !ReadOnly_CurrentPPCOLMask) 
	 return -1;

 //First we do normal bounding box collision detection...
 if( !check_bb_collision(mask1, this->ReadOnly_CurrentPPCOLMask, mask1_x,mask1_y, this_x, this_y) ) //If there is not bounding box collision...
   return 0; //return that there is not collision...

 //Now we do pixel perfect collision detection...

 //First we need to see how much we have to shift the coordinates of the masks...
 if(mask1_x>this_x) {
   dx1=0;      //don't need to shift mask 1.
   dx2=mask1_x-this_x;  //shift mask 2 left. Why left? Because we have the mask 1 being on the right of the mask 2, so we have to move mask 2 to the left to do the proper pixel perfect collision...
   } else {
   dx1=this_x-mask1_x;  //shift mask 1 left.
   dx2=0;      //don't need to shift mask 2.
   }
 if(mask1_y>this_y) {
   dy1=0;
   dy2=mask1_y-this_y;  //we need to move this many rows up mask 2. Why up? Because we have mask 1 being down of mask 2, so we have to move mask 2 up to do the proper pixel perfect collision detection...
   } else {
   dy1=this_y-mask1_y;  //we need to move this many rows up mask 1.
   dy2=0;
   }

 //We need to initialize this values first...
 chunkm1 = dx1/32; //This sets the starting chunk number...
 chunkm2 = dx2/32;
 chunkm1p = dx1 - (32*chunkm1); //This sets the value we have to shift the chunks of this mask...
 chunkm2p = dx2 - (32*chunkm2);

 //This will calculate the maximum height that we will reach...
 if(mask1->h-dy1 > ReadOnly_CurrentPPCOLMask->h-dy2) {
   maxh=this->ReadOnly_CurrentPPCOLMask->h-dy2;
   } else {
   maxh=mask1->h-dy1;
   }
 maxh--;

 //Now we start the actual pixel perfect collision detection loop...
 while( (chunkm1<=mask1->max_chunk) && (chunkm2<=this->ReadOnly_CurrentPPCOLMask->max_chunk) ) { //While there remains more chunks in the 2 masks we continue doing the ppcol detection...
   for(py=maxh;py>=0;py--) { //Test for all rows...
     if( (mask1->sp_mask[dy1+py][chunkm1] << chunkm1p) & (this->ReadOnly_CurrentPPCOLMask->sp_mask[dy2+py][chunkm2] << chunkm2p) ) //If bits of the mask coincides, we have a collision!
       return 2; //Return that there is a collision!
     }
   //Now we have to move to the next chunk...
   if( (!chunkm1p) && (!chunkm2p) ) { //In case both masks are lined up on the x axis...
     chunkm1++; //Increment both chunks...
     chunkm2++;
     } else {
     if(!chunkm1p) { //If the mask 1 don't need shifting...
       chunkm2++;
       chunkm1p = 32 - chunkm2p;
       chunkm2p = 0;
       } else {
       if(!chunkm2p) {
         chunkm1++;
         chunkm2p = 32 - chunkm1p;
         chunkm1p = 0;
         }
       }
     }

   } //There are no more chunks to test...
 //We haven't found a collision... so, return 1 as there was a bounding box
 return 1;
 }
#endif
	
AnimationLibraryFrame::AnimationLibraryFrame(AnimationLibraryFrames* const parent, const string& filein, int typeOfBitmap, 
	int msWait, int fWait, int isasheetgraphic, int originx, int originy, int tilex, int tiley, 
	int sheetitemwidth, int sheetitemheight,bool hasaPPCOLmask)
{
	ostringstream ss;
	string file=filein;
	ss << file;
	AnimationLibrary::LogEntry("Animation Frame Constructor: "+ss.str(),false,"animation.log");
	File=file;
	PPCOLMask=NULL;
#if (USE_OPENLAYER==1)
	FrameCollisionPoly=NULL;
#endif
	//DataEntry=dataentry;
	MSWait=msWait;
	FWait=fWait;
	IsASheetGraphic=isasheetgraphic;
	OriginX=originx;
	OriginY=originy;
	TileX=tilex;
	TileY=tiley;
	SheetItemWidth=sheetitemwidth;
	SheetItemHeight=sheetitemheight;
	Image=NULL;
	CreatedOk=true;
	HasPPCOLMask=hasaPPCOLmask;
	
	if(parent)
	{
		//get parent
		if(MSWait<0) MSWait=parent->DefaultMilliSecondWait;
		if(FWait<0) FWait=parent->DefaultFrameWait;
		if(isasheetgraphic<0) 
			IsASheetGraphic=isasheetgraphic=parent->DefaultIsASheetGraphic;
			
		if(OriginX<0) OriginX=parent->DefaultOriginX;
		if(OriginY<0) OriginY=parent->DefaultOriginY;
		if(file=="") file=parent->DefaultFileName;
		if(SheetItemWidth<0) SheetItemWidth=parent->DefaultSheetWidth;
		if(SheetItemHeight<0) SheetItemHeight=parent->DefaultSheetHeight;

		//bitmap type
#if (USE_OPENLAYER==1)
		TypeOfBitmap=TYPE_VIDEO;
#else
		if(typeOfBitmap==-1) TypeOfBitmap=parent->DefaultTypeOfBitmap;
		else
		{
			switch(typeOfBitmap)
			{
			    case 2:
			    	    this->TypeOfBitmap=TYPE_SYSTEM;
			    	    break;
			    case 3:
			    	    this->TypeOfBitmap=TYPE_VIDEO;
			    	    break;
			    default:
			    	    this->TypeOfBitmap=TYPE_MEMORY;
			    	    break;
		     }
		}
#endif
	}
	else
		//no parent animation therefore can only use the animation static
#if (USE_OPENLAYER==1)
		TypeOfBitmap=TYPE_VIDEO;
#else
		TypeOfBitmap=AnimationLibrary::DefaultTypeOfBitmap;
	//cap graphics	
	if(TypeOfBitmap>AnimationLibrary::MaxTypeOfBitmap)
	//if(TypeOfBitmap==TYPE_SYSTEM || TypeOfBitmap==TYPE_VIDEO)
	{
		//change type if requested graphic is system or video as is higher than max or the same as max
		TypeOfBitmap=AnimationLibrary::MaxTypeOfBitmap;
		AnimationLibrary::LogEntry("Bitmap type requested was higher than allowed, reducing down",false,"animation.log");
	}
#endif
	
	//get global if still empty
	if(MSWait<0) MSWait=AnimationLibrary::DefaultMilliSecondWait;
	if(FWait<0) FWait=AnimationLibrary::DefaultFrameWait;
	if(isasheetgraphic<0) IsASheetGraphic=AnimationLibrary::DefaultIsASheetGraphic;
	if(OriginX<0) OriginX=0;
	if(OriginY<0) OriginY=0;
	//still one more!
	if(MSWait<0 && FWait<0) MSWait=0;

	if(file=="")
	{
		AnimationLibrary::LogEntry("File is empty, cannot create object",false,"animation.log");
		CreatedOk=false;
	}
	else
	{
		char filechar[255];
		sprintf(filechar,"%s%s","gfx\\",file.c_str());
		string filename=fix_filename_slashes( filechar );

		//if a file is referenced > once we don't really want to load it into memory again
		//so using a map to store the bitmap pointers using the filename as the key
		map<string,AXL_BITMAP*>::const_iterator BitmapIterator;

		BitmapIterator=AnimationLibrary::StoredBitmaps.find(file);

		//if graphic doesn't exist, create it
		//otherwise point in the right place
		if(BitmapIterator==AnimationLibrary::StoredBitmaps.end())
		{
			if(!isasheetgraphic)
			{
				//not a sub bitmap so load it
				//also only non-subbitmaps get added to the collection
				if(parent->BitmapCreator) 
				{
					Image=parent->BitmapCreator(filename);
				}
				else
				{
#if (USE_OPENLAYER!=1)
					this->Image=load_bmp(filename.c_str(),NULL);
#else
//					NEED to update with use magic pink
                    if(hasaPPCOLmask)
                    {
                         Image=new Bitmap(filename.c_str(),CREATE_COLLISION_POLY);                    
                         if(Image)
                          FrameCollisionPoly=Image->GetCollisionPoly();
                         else
                          FrameCollisionPoly=NULL;
                    }
                    else
                    {
                         Image=new Bitmap(filename.c_str());                    
                        {
                             //Image=new Bitmap(tmp->w,tmp->h,Rgba::RED);
                             //FrameCollisionPoly=new Poly();
                             //FrameCollisionPoly->Add(Vec2D(0,0));
                             //FrameCollisionPoly->Add(Vec2D(Image->Width()-1,0));
                             //FrameCollisionPoly->Add(Vec2D(Image->Width()-1,Image->Height()-1));
                             //FrameCollisionPoly->Add(Vec2D(0,Image->Height()-1));
                             FrameCollisionPoly=NULL;
                        }
                    }
#endif
				}
					
				ss << " Image: " << Image;
				AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
				if(this->Image!=NULL)
				{				
#if (USE_OPENLAYER!=1)
					//convert if necessary
					AXL_BITMAP* tmp=NULL;
					switch(TypeOfBitmap)
					{
					    case 3:	//try video if set
				    	    AnimationLibrary::LogEntry("Bitmap wanted to be Video",false,"animation.log");
				    	    tmp=create_video_bitmap(Image->w,Image->h);
					    	blit(Image,tmp,0,0,0,0,Image->w,Image->h);
				    	    if(tmp)
				    	    {
					    		destroy_bitmap(Image);
					    		Image=tmp;
								AnimationLibrary::LogEntry("Got video",false,"animation.log");
								ss.str("");
								ss << "New Image after video conversion is " << Image;
  					  		 	break;  					  		 	
			              	}
			              //else follow down to try system
					    case 2:
				    	    AnimationLibrary::LogEntry("Bitmap wanted to be System",false,"animation.log");
				    	    tmp=create_system_bitmap(Image->w,Image->h);
					    	blit(Image,tmp,0,0,0,0,Image->w,Image->h);
				    	    if(tmp)
				    	    {
					    		destroy_bitmap(Image);
					    		Image=tmp;
								ss.str("");
								ss << "New Image after system conversion is " << Image;
				    	    	AnimationLibrary::LogEntry("Got System",false,"animation.log");
				    	    	AnimationLibrary::LogEntry("WARNING: IF SUBBITMAPS ARE CREATED (THIS IS A MASTER SHEET) THEN UNLESS A VERSION IS AVAILABLE, THE SYSTEM WILL CRASH ON DESTRUCTION OF THE SUB-BITMAPS",false,"animation.log");
					    		break;
				        	}
					    default:	//memory
				    	    AnimationLibrary::LogEntry("Bitmap Type Default of Memory type",false,"animation.log");
	    			         //no need to change as Image is a standard memory bitmap
				    	    break;
					}
#endif
					//add to end
					AnimationLibrary::StoredBitmaps[file]=Image;
					AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
				}
				else
				{
					AnimationLibrary::LogEntry("Loading of image failed.",false,"animation.log");
					CreatedOk=false;
				}
			}
			else
			{
				AnimationLibrary::LogEntry("bitmap is a sheet graphic but the master does not exist. cannot create.",false,"animation.log");
				CreatedOk=false;
			}
		}
		else
		{
			if(!isasheetgraphic)
			{
				AnimationLibrary::LogEntry("bitmap already used, passing reference not loading and keeping old Bitmap Type",false,"animation.log");
				this->Image=BitmapIterator->second;
			}
			else
			{
				//sheet graphic and the master was found, create the offsets
				//if no parent then assume not a tiled system as parent details do not exist or tile set to off
				//if a parent and not a grid
				if(parent==NULL || (parent!=NULL && (TileX<0 || TileY<0)) )
				{
					//no parent, must be a subbitmap
					//has a parent but no tile position, must be a subbitmap
#if (USE_OPENLAYER!=1)
					Image=create_sub_bitmap(BitmapIterator->second, OriginX,OriginY, SheetItemWidth,SheetItemHeight);
#else
					Image=new Bitmap(*(BitmapIterator->second),Rect(OriginX,OriginY,SheetItemWidth,SheetItemHeight));
                    if(hasaPPCOLmask && Image)
                    {
						//cannot create collision masks yet for sub-bitmaps
						//use bounding box for now
                         FrameCollisionPoly=new Poly();
                         FrameCollisionPoly->Add(Vec2D(0,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,Image->Height()-1));
                         FrameCollisionPoly->Add(Vec2D(0,Image->Height()-1));
                    }
                    else
                    {
                         FrameCollisionPoly=new Poly();
                         FrameCollisionPoly->Add(Vec2D(0,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,Image->Height()-1));
                         FrameCollisionPoly->Add(Vec2D(0,Image->Height()-1));
                    }                        
#endif
					AnimationLibrary::LogEntry("Sub-Bitmap is offset from a master and uses that bitmap type",false,"animation.log");
					ss.str("");
					ss << "Master image is " << BitmapIterator->second;
					AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
					ss.str("");
				}
				else
				{
					//has a parent and tile position
					int calcStartX, calcStartY;
					calcStartX=OriginX+((SheetItemWidth+(parent->DefaultSheetGrid?1:0))*TileX)+(parent->DefaultSheetGrid?1:0);	//1 pixel for grid
					calcStartY=OriginY+((SheetItemHeight+(parent->DefaultSheetGrid?1:0))*TileY)+(parent->DefaultSheetGrid?1:0);	//1 pixel for grid

					//parent is populated and using a grid
					AnimationLibrary::LogEntry("Sub-Bitmap is tiled from a master and uses that bitmap type",false,"animation.log");
					ss.str("");
					ss << "Master image is " << BitmapIterator->second;
					AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
#if (USE_OPENLAYER!=1)
					Image=create_sub_bitmap(BitmapIterator->second, calcStartX,calcStartY, SheetItemWidth,SheetItemHeight);
#else
					Image=new Bitmap(*(BitmapIterator->second),Rect(calcStartX,calcStartY,SheetItemWidth,SheetItemHeight));
                    if(hasaPPCOLmask && Image)
                    {
						//cannot create collision masks yet for sub-bitmaps
                                     FrameCollisionPoly=Image->GetCollisionPoly();
                    }
                    else
                    {
                         FrameCollisionPoly=new Poly();
                         FrameCollisionPoly->Add(Vec2D(0,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,0));
                         FrameCollisionPoly->Add(Vec2D(Image->Width()-1,Image->Height()-1));
                         FrameCollisionPoly->Add(Vec2D(0,Image->Height()-1));
                    }
#endif
					//Image=create_sub_bitmap(BitmapIterator->second, 1,1, 32,56);
					ss.str("");
					ss << "tile x/y: " << TileX << "," << TileY << " W/H: " << SheetItemWidth << "," << SheetItemHeight << " Calc X/Y: " << calcStartX << "," << calcStartY << " Image: " << Image;
					AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
				}

				if(this->Image!=NULL)
				{
					AnimationLibrary::LogEntry("Parent image is: "+file,false,"animation.log");
#if (USE_OPENLAYER!=1)
			 	    if(is_video_bitmap(BitmapIterator->second)) AnimationLibrary::LogEntry("bitmap type is Video as this Sub-Bitmap's parent is Video",false,"animation.log");
			 	    if(is_system_bitmap(BitmapIterator->second)) AnimationLibrary::LogEntry("bitmap type is System as this Sub-Bitmap's parent is System",false,"animation.log");
			 		if(is_memory_bitmap(BitmapIterator->second)) AnimationLibrary::LogEntry("bitmap type is Memory as this Sub-Bitmap's parent is Memory",false,"animation.log");
#else
					AnimationLibrary::LogEntry("bitmap type is Video as this Sub-Bitmap's parent is Video and using OpenLayer",false,"animation.log");
#endif
					AnimationLibrary::LogEntry("Sub-Bitmap created",false,"animation.log");
					//ostringstream fs;
					//dont add to list as never need to find it
					//but destructor must always delete it
					//AnimationLibraryFrame::StoredBitmaps[file]=this->Image;
					//clear(screen);
					//blit(Image,screen,TileX*32,TileY*32,0,0,Image->w,Image->h);
					//readkey();
					//clear_keybuf();
				}
				else
				{
					AnimationLibrary::LogEntry("Creation of sub-bitmap failed.",false,"animation.log");
					CreatedOk=false;
				}
			}
		}
	}
	if(HasPPCOLMask) AnimationLibrary::LogEntry("PPCOL/CollisionMask To Be Created",false,"animation.log");

	if(CreatedOk && HasPPCOLMask)
		CreatePPCOLMask();
}

//code taken from ppmask samples
bool AnimationLibraryFrame::CreatePPCOLMask()
{
#if (USE_OPENLAYER!=1)
	PPCOL_MASK *maskout;
	int INTVAR, INTVAR2, INTVAR3; //We will use this temporary...

	AnimationLibrary::LogEntry("Creating PPCOL_MASK",false,"animation.log");
	HasPPCOLMask=false;

	if(!Image)   //User passes an uninitialized sprite...
	{
		AnimationLibrary::LogEntry("PPCOL not created. Image null",false,"animation.log");
		return false;
	}

	//We have to allocate the memory for the structure fields...
	//               Size of structure  + size of pointers to rows of chunks * number of sprite rows.
	maskout = (PPCOL_MASK*)malloc(sizeof(PPCOL_MASK) + (sizeof(unsigned long int *) * Image->h) );
	if(!maskout)  //maskout structure allocation failed!
	{		
		AnimationLibrary::LogEntry("PPCOL not created. structure allocation",false,"animation.log");
		return false;
	}

	//Now we initialize some of the fields of the structure...
	maskout->h = Image->h;
	maskout->w = Image->w;
	//                 not divisible by 32?       yes:              no:
	//Chunks are 32 pixels... so w/32... max_chunks are the maximum number of chunks -1, 
	//so if divisible by 32: w/32-1, if not divisible by 32: w/32.
	maskout->max_chunk = ( (Image->w%32) ? (Image->w/32) : (Image->w/32-1) ); 

	//Now that we have some more data, we allocate the mask data...
	maskout->dat = malloc( (maskout->max_chunk+1) * 4 * Image->h );
	if(!maskout->dat) //data allocation failed!
	{
		AnimationLibrary::LogEntry("PPCOL not created. data allocation",false,"animation.log");
		free(maskout); //Free the structure kernel data.
		return false;
	}

	//We are going to initialize the array of pointers to the begining of each row of chunks...
	maskout->sp_mask[0] = (unsigned long*)maskout->dat; //The first pointer points to the begining of the data...
	for(INTVAR=1; INTVAR < maskout->h; INTVAR++) //Now initialize all the other pointers...
	maskout->sp_mask[INTVAR]=maskout->sp_mask[INTVAR-1] + (maskout->max_chunk+1); //the position of the previous pointer + number of the chunks.

	//Now we have a proper mask structure allocated and mostly initialized, but the mask data has garbage! We have to initialize it to 0's:
	for(INTVAR=maskout->h-1; INTVAR>=0; INTVAR--) {
	for(INTVAR2=maskout->max_chunk; INTVAR2>=0; INTVAR2--) {
		maskout->sp_mask[INTVAR][INTVAR2]=0;
		}
	}

	//Now we have to create the bit mask array for the sprite:
	for(INTVAR=0; INTVAR < maskout->h; INTVAR++) { //Row loop...
	for(INTVAR2=0; INTVAR2 <= maskout->max_chunk; INTVAR2++) { //Chunk loop...
		for(INTVAR3=INTVAR2*32; INTVAR3 < (INTVAR2*32+32); INTVAR3++) { //Loop between the pixels that the current chunk covers...
			if( INTVAR3<Image->w ) { //Check if we are in range in the X axis... because if we pass it, getpixel would return a bad return value...
			if( getpixel(Image, INTVAR3, INTVAR) != bitmap_mask_color(Image) ) { //The pixel is not a mask color... so we have to check for collision, so we add it to the bitarray in the current chunk...
				//maskout->sp_mask[INTVAR][INTVAR2] += 0x80000000 >> ( INTVAR3 - (INTVAR2+1)*32 ); //This was the original from Neil.
				
				//This seems more correct... 
				//0x80000000 == 0b10000000000000000000000000000000, we shift this bit to the right position where it must be in the 
				//current chunk, this indicates that there is a pixel that we must check for collision.
				maskout->sp_mask[INTVAR][INTVAR2] |= 0x80000000 >> ( INTVAR3 - (INTVAR2)*32 ); 
				}
			}
			}
		}
	}

	//We have allocated the memory for a mask for the given sprite, we have initialized it and filled the mask bit data with correct data... so this is the end of this function! Don't you think?
	PPCOLMask=maskout;
	HasPPCOLMask=true;
	AnimationLibrary::LogEntry("PPCOL created.",false,"animation.log");
#endif

	return true; 
}

//code taken from ppmask samples
void AnimationLibraryFrame::DeletePPCOLMask()
{
//This is the mask deallocation routine, pass it a PPCOL_MASK pointer and it
//will be deallocated from memory. If the passed pointer was already
//deallocated or not allocated at all, this function does nothing.
	if(PPCOLMask) { //Mask is not NULL? Mask is allocated?
		if(PPCOLMask->dat) free(PPCOLMask->dat); //Deallocate the data if it was not deallocated...
		free(PPCOLMask); //Deallocate the mask structure...
		AnimationLibrary::LogEntry("Mask Deleted",false,"animation.log");
	}
	HasPPCOLMask=false;
	PPCOLMask=NULL;
}

AnimationLibraryFrame::~AnimationLibraryFrame(void)
{
	//only delete image if it is a sub-bitmap
	//non-subbitmaps could be referenced by other animationframes
	//so only delete these when the library is deleted
	ostringstream ss;

	if(Image!=NULL) 
	{
		ss << File << ":" << Image;
		if(this->IsASheetGraphic)
		{
			//always delete sub bitmaps as never a link to another, or we assume not
			AnimationLibrary::LogEntry("Animation Frame Destructor: A Sub: "+ss.str(),false,"animation.log");
#if (USE_OPENLAYER!=1)
			destroy_bitmap(Image);
#else
       if(FrameCollisionPoly) delete FrameCollisionPoly;
		Image->Destroy();
		delete Image;
#endif
			//clear(screen);
			//draw_sprite(screen,Image,0,0);
			//readkey();
		}
		else
		{
			map<string,AXL_BITMAP*>::iterator BitmapIterator;
			BitmapIterator=AnimationLibrary::StoredBitmaps.find(this->File);
			if(BitmapIterator!=AnimationLibrary::StoredBitmaps.end())
			{
				AnimationLibrary::LogEntry("Animation Frame Destructor not destroying image yet as a File not a subbitmap: "+ss.str(),false,"animation.log");
			}
			else
			{
				AnimationLibrary::LogEntry("Animation Frame Destructor destroying image. not a sub but not in stored list: "+ss.str(),false,"animation.log");
#if (USE_OPENLAYER!=1)
				destroy_bitmap(Image);
#else
				Image->Destroy();
				delete Image;
#endif
				AnimationLibrary::StoredBitmaps.erase(BitmapIterator);
			}
		}
		DeletePPCOLMask();
	}
	else
		AnimationLibrary::LogEntry("Animation Frame Destructor Not Called: "+ss.str(),false,"animation.log");

}

AnimationLibraryFrames::AnimationLibraryFrames(const string& id, LoopType lt,int msWait, 
						int fWait,bool autom, int depth, int dox, int doy, 
						int dsg, int dsw, int dsh, int disa, int dbtype, const string& filename, bool hasaPPCOLmask)
{
	ostringstream ss;
	ss << id;
	AnimationLibrary::LogEntry("Animation Frames Constructor: "+ss.str(),false,"animation.log");

	BitmapCreator=NULL;
	if(dox<0) dox=0;
	if(doy<0) doy=0;
	//if(dtx<0) dtx=0;
	//if(dty<0) dty=0;

	Id=id;
	Loop=lt;
	AutoMove=OriginalAutoMove=autom;
	OriginalLoop=lt;

	DefaultMilliSecondWait=msWait;
	DefaultFrameWait=fWait;
	DefaultSheetWidth=dsw;
	DefaultSheetHeight=dsh;
	DefaultSheetGrid=(dsg==1);
	DefaultOriginX=dox;
	DefaultOriginY=doy;
	
	if(dsg<0) DefaultSheetGrid=AnimationLibrary::DefaultSheetGrid;
	if(disa<0) DefaultIsASheetGraphic=AnimationLibrary::DefaultIsASheetGraphic;
	else DefaultIsASheetGraphic=(disa==1);
	
	DefaultFileName=filename;
	DefaultHasPPCOLMask=hasaPPCOLmask;

	//milliseconds takes priority and only framecount is required from now on
	this->DefaultColourDepth=depth;

	if(depth==-1) DefaultColourDepth=AnimationLibrary::DefaultColourDepth;
	if(dsw<0) DefaultSheetWidth=AnimationLibrary::DefaultSheetWidth;
	if(dsh<0) DefaultSheetHeight=AnimationLibrary::DefaultSheetHeight;
	if(dox<0) DefaultOriginX=0;
	if(doy<0) DefaultOriginY=0;
	
#if (USE_OPENLAYER==1)
			DefaultTypeOfBitmap=TYPE_VIDEO;
#else
	if(dbtype==-1) DefaultTypeOfBitmap=AnimationLibrary::DefaultTypeOfBitmap;
	else
	{
		switch(dbtype)
		{
		    case 2:
		    	    this->DefaultTypeOfBitmap=TYPE_SYSTEM;
		    	    break;
		    case 3:
		    	    this->DefaultTypeOfBitmap=TYPE_VIDEO;
		    	    break;
		    default:
		    	    this->DefaultTypeOfBitmap=TYPE_MEMORY;
		    	    break;
	     }
	}
#endif
}

AnimationLibraryFrames::~AnimationLibraryFrames(void)
{
	ostringstream ss;
	ss << Id;
	AnimationLibrary::LogEntry("Animation Frames Destructor: "+ss.str(),false,"animation.log");

	//delete all frames from memory
	vector<AnimationLibraryFrame*>::iterator AnimationIterator;
	for(AnimationIterator=this->FrameItems.begin(); AnimationIterator!=FrameItems.end();AnimationIterator++)
	{
		delete (*AnimationIterator);
	}

	FrameItems.clear();
}

bool AnimationLibraryFrames::AddAnimationFrame(AnimationLibraryFrame* const ai)
{
	ostringstream ss;
	ss << ai->File << " : " << ai->Image;
	if(ai->FWait<0) ai->FWait=this->DefaultFrameWait;
	if(ai->MSWait<0) ai->MSWait=this->DefaultMilliSecondWait;

	if(ai->Image==NULL)
	{
		AnimationLibrary::LogEntry("Animation frame not added as no file/datafile entry",false,"animation.log");
		delete ai;
		return false;
	}
	else
	{
		this->FrameItems.push_back(ai);
		AnimationLibrary::LogEntry((string)"Animation frame added: "+ss.str(),false,"animation.log");
	}
	return true;
}
AnimationLibraryFrames* AnimationLibrary::GetAnimation(const string& id) const
{
	//return a pointer to an animation
	//speeded up if called at start of game to initiase commonly used
	//animations
	map<string,AnimationLibraryFrames*>::const_iterator AnimationIterator;

	AnimationIterator=AnimationFrames.find(id);
	if(AnimationIterator==AnimationFrames.end())
		return NULL;
	else
		return AnimationIterator->second;
}

AnimationLibrary::AnimationLibrary(const std::string& file, int fps, BitmapType maxbmp,AXL_BITMAP* (*bitmapcreator)(const std::string&))
{

	AnimationLibrary::DefaultColourDepth=32;
	AnimationLibrary::DefaultMilliSecondWait=0;
	AnimationLibrary::DefaultFrameWait=-1;
	AnimationLibrary::DefaultLoop=LOOP_ONCE;
	AnimationLibrary::DefaultHasPPCOLMask=false;
	AnimationLibrary::DefaultAutoMove=true;
	AnimationLibrary::DefaultSheetGrid=false;
	AnimationLibrary::DefaultSheetWidth=64;
	AnimationLibrary::DefaultSheetHeight=64;
	AnimationLibrary::DefaultIsASheetGraphic=false;

	AnimationLibrary::MaxTypeOfBitmap=maxbmp;
	
	AnimationLibrary::DefaultTypeOfBitmap=TYPE_VIDEO;

	this->BitmapCreator=bitmapcreator;
	
	this->fps=fps;
	AnimationLibrary::LogEntry("Animation Library Constructor",true,"animation.log");
	ostringstream ss;
	ss<<fps;
	AnimationLibrary::LogEntry("Animation FPS set to " + ss.str(),false,"animation.log");
	ss.str("");
	ss << "Maximum animation graphic will be " << AnimationLibrary::MaxTypeOfBitmap;
	AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
	
	//seems as good as any fblend define to use to check it's existance
#if(USE_FBLEND==1)
	AnimationLibrary::LogEntry((string)"Animation using FBlend version "+FBLEND_VERSION_STRING,false,"animation.log");
#else
	AnimationLibrary::LogEntry("Animation Not using FBlend. ",false,"animation.log");
#endif
#if (USE_OPENLAYER!=1)
	AnimationLibrary::LogEntry("Using Standard Allegro",false,"animation.log");
#else
	AnimationLibrary::LogEntry("Using OpenLayer",false,"animation.log");
#endif

	if(LoadAnimations(file))
		LogEntry("End of Constructor. Load OK",false,"animation.log");
	else
	{
		LogEntry("End of Constructor. Load Fail",false,"animation.log");
		SetGlobalErrorString("Failed to load animations.");
		LoadError=true;
	}
}

AnimationLibrary::~AnimationLibrary(void)
{
	AnimationLibrary::LogEntry("Animation Library Destructor",false,"animation.log");
	DestroyAll();
}

//debug function
void AnimationLibrary::draw() const
{
	map<string,AnimationLibraryFrames*>::const_iterator AnimationIterator;
	vector<AnimationLibraryFrame*>::const_iterator AnimationIterator2;
    for (AnimationIterator = AnimationFrames.begin(); AnimationIterator!= AnimationFrames.end(); AnimationIterator++)
	{
		for (AnimationIterator2 = (AnimationIterator->second)->FrameItems.begin(); AnimationIterator2!= (AnimationIterator->second)->FrameItems.end(); AnimationIterator2++)
		{
#if (USE_OPENLAYER!=1)
			clear(screen);
			blit((*AnimationIterator2)->Image,screen,0,0,0,0,(*AnimationIterator2)->Image->w,(*AnimationIterator2)->Image->h);
			//draw_sprite(screen,(*AnimationIterator2)->Image,0,0);
			textprintf_ex(screen,font,0,50,makecol(255,0,0),-1,"%x",(unsigned int)(*AnimationIterator2)->Image);
#else
			(*AnimationIterator2)->Image->Blit(0,0);
			//textprintf_ex(screen,font,0,50,makecol(255,0,0),-1,"%x",(unsigned int)(*AnimationIterator2)->Image);
			Canvas::Refresh();
#endif
			readkey();
		}
	}
}

void AnimationLibrary::DestroyAll()
{
	ostringstream ss;
	AnimationLibrary::LogEntry("Destroying All Animations",false,"animation.log");
	map<string,AnimationLibraryFrames*>::iterator AnimationIterator;

	LoadError=false;
	for (AnimationIterator = AnimationFrames.begin(); AnimationIterator!= AnimationFrames.end(); AnimationIterator++)
        delete AnimationIterator->second;

	AnimationFrames.clear();

	//now delete all permanent bitmaps
	map<string,AXL_BITMAP*>::const_iterator StoredItemsIterator;
	for(StoredItemsIterator=AnimationLibrary::StoredBitmaps.begin();
		StoredItemsIterator!=AnimationLibrary::StoredBitmaps.end();
		StoredItemsIterator++)
	{
		ss.str("");
		ss << "Destroying non subbitmap " << StoredItemsIterator->first << " : " << StoredItemsIterator->second;
		AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
#if (USE_OPENLAYER!=1)
		destroy_bitmap(StoredItemsIterator->second);
#else
		StoredItemsIterator->second->Destroy();
		delete StoredItemsIterator->second;
#endif
		AnimationLibrary::LogEntry("done deleting",false,"animation.log");
	}
	AnimationLibrary::StoredBitmaps.clear();
}

bool AnimationLibrary::AddAnimation(AnimationLibraryFrames* const animation)
{
	//add an animation to the list. automove is set to manual if no timings set up
	if(animation==NULL) return false;

	if(animation->Id=="")
	{
		AnimationLibrary::LogEntry("Animation not added as no id set",false,"animation.log");
		delete animation;
		return false;
	}
	if(animation->FrameItems.size()==0)
	{
		ostringstream ss;
		ss << animation->Id;
		AnimationLibrary::LogEntry("Animation removed as no frames are present: "+ss.str(),false,"animation.log");
		delete animation;
		return false;
	}
	if(animation->DefaultFrameWait<0) animation->DefaultFrameWait=AnimationLibrary::DefaultFrameWait;
	if(animation->DefaultMilliSecondWait<0) animation->DefaultMilliSecondWait=AnimationLibrary::DefaultMilliSecondWait;
	if(animation->Loop==LOOP_INVALID) animation->Loop=AnimationLibrary::DefaultLoop;
	if(animation->Loop==LOOP_INVALID) animation->Loop=LOOP_START;	//fall back

	if(animation->DefaultTypeOfBitmap==-1) animation->DefaultTypeOfBitmap=AnimationLibrary::DefaultTypeOfBitmap;
	
	if(animation->DefaultMilliSecondWait<=0 && animation->DefaultFrameWait<=0)
	{
		animation->DefaultMilliSecondWait=animation->DefaultFrameWait=0;
	}

	if(animation->DefaultMilliSecondWait<=0 || animation->DefaultFrameWait<=0)
		animation->AutoMove=false;

	//sheet/tile stuff
	if(animation->DefaultOriginX==-1) animation->DefaultOriginX=0;
	if(animation->DefaultOriginY==-1) animation->DefaultOriginY=0;
	if(animation->DefaultSheetHeight==-1) animation->DefaultSheetHeight=AnimationLibrary::DefaultSheetHeight;
	if(animation->DefaultSheetWidth==-1) animation->DefaultSheetWidth=AnimationLibrary::DefaultSheetWidth;

	//set time to 0 so can set frame rate properly
	if (AnimationLibrary::DefaultMilliSecondWait==-1 && AnimationLibrary::DefaultFrameWait==-1) 
		AnimationLibrary::DefaultMilliSecondWait=0;

	//evaluate the wait time if only ms is set
	if(animation->DefaultFrameWait==-1 && animation->DefaultMilliSecondWait>=0)
	{
		AnimationLibrary::LogEntry("animation: "+animation->Id+" framewait set from ms and fps",false,"animation.log");
		if(animation->DefaultMilliSecondWait==0) animation->DefaultFrameWait=0;
		else
			animation->DefaultFrameWait=(fps*animation->DefaultMilliSecondWait)/1000;
	}

	//add the animation
	AnimationLibrary::LogEntry((string)"animation "+animation->Id+(string)" added",false,"animation.log");
	this->AnimationFrames[animation->Id]=animation;

	//resolve any animation frame settings now
	if(animation->Loop==LOOP_INVALID) animation->Loop=AnimationLibrary::DefaultLoop;

	//set all frames correctly
	
	vector<AnimationLibraryFrame*>::const_iterator AnimationIterator;
    for (AnimationIterator = animation->FrameItems.begin(); AnimationIterator!= animation->FrameItems.end(); AnimationIterator++)
	{
		//no need to check mswait as fwait will always be set
        if((*AnimationIterator)->FWait==-1)
		{
			(*AnimationIterator)->FWait=animation->DefaultFrameWait;
			(*AnimationIterator)->MSWait=animation->DefaultMilliSecondWait;
		}
	}
	return true;
}

bool AnimationLibrary::LoadAnimations(const string &file)
{
	//load animations from file
	TiXmlDocument doc;
	TiXmlElement* node;
	TiXmlNode* nodule;
	TiXmlElement* innernode;
	TiXmlNode* innernodule;

	ostringstream ss;

	ss << "Loading Animation XML";
	SetGlobalErrorString("");
	AnimationLibrary::LogEntry("--------------",false,"animation.log");
	AnimationLibrary::LogEntry(ss.str(),false,"animation.log");
	AnimationLibrary::LogEntry("--------------",false,"animation.log");

	DestroyAll();

	//try to see if its a string first
	doc.Parse(file.c_str());
	if(doc.Error())
	{
		LogEntry("Entry failed to parse as a string so assuming it is a file",false,"animation.log");
		if(!doc.LoadFile(file.c_str()))
		{
			AnimationLibrary::LogEntry((string)"Initialised Animation library as a file failed. check it is valid XML:"+ doc.ErrorDesc(),false,"animation.log");
			LoadError=true;
			return false;
		}
		else
			AnimationLibrary::LogEntry("Initialised Animation FILE using "+file,false,"animation.log");

		AnimationLibrary::LogEntry("Processing animation file (loaded and/or parsed ok). Checking attribute syntax.",false,"animation.log");
	}
	else
		AnimationLibrary::LogEntry("Initialised Animation as a string BUFFER ",false,"animation.log");

	TiXmlElement* map=doc.RootElement();

	const char* bmp_file=NULL;
	int ms=-1;
	int fw=-1;
	const char* loop=NULL;
	const char* id=NULL;
	int automode=1;
	LoopType lt=LOOP_START;
	bool ok=true;
	int depth=-1;
	//sheet stuff
	int swidth=64;
	int sheight=64;
	int sgrid=false;
	int isasheetgraphic=false;
	int hasaPPCOLmask=false;
	int bitmaptype=1;
	int sequencecount=0;

	//global
	TiXmlElement* globals=map->FirstChildElement("global")->ToElement();
	if(globals==NULL) 
		AnimationLibrary::LogEntry("No XML global section found. using defaults",false,"animation.log");
	else
	{
		AnimationLibrary::LogEntry("Reading Globals",false,"animation.log");
		if(globals->QueryIntAttribute("depth",&depth)==TIXML_SUCCESS) AnimationLibrary::DefaultColourDepth=depth;
		if(globals->QueryIntAttribute("millisecondwait",&ms)==TIXML_SUCCESS) AnimationLibrary::DefaultMilliSecondWait=ms;
		if(globals->QueryIntAttribute("framewait",&fw)==TIXML_SUCCESS) AnimationLibrary::DefaultFrameWait=fw;
		if(globals->QueryIntAttribute("automode",&automode)==TIXML_SUCCESS) AnimationLibrary::DefaultAutoMove=(automode==1?true:false);
		if(globals->QueryIntAttribute("sheetgrid",&sgrid)==TIXML_SUCCESS) this->DefaultSheetGrid=(sgrid==1);
		if(globals->QueryIntAttribute("isasheetgraphic",&isasheetgraphic)==TIXML_SUCCESS) AnimationLibrary::DefaultIsASheetGraphic=(isasheetgraphic==1);
		if(globals->QueryIntAttribute("sheetitemwidth",&swidth)==TIXML_SUCCESS) AnimationLibrary::DefaultSheetWidth=swidth;
		if(globals->QueryIntAttribute("sheetitemheight",&sheight)==TIXML_SUCCESS) AnimationLibrary::DefaultSheetHeight=sheight;
		if(globals->QueryIntAttribute("ppmask",&hasaPPCOLmask)==TIXML_SUCCESS) AnimationLibrary::DefaultHasPPCOLMask=(hasaPPCOLmask==1);
		if(globals->QueryIntAttribute("bmp_type",&bitmaptype)==TIXML_SUCCESS) 
		{
#if (USE_OPENLAYER!=1)
		    switch(bitmaptype)
		    {
				  case(3):
				  	AnimationLibrary::DefaultTypeOfBitmap=TYPE_VIDEO;
				  	break;
		  		case(2):
				  	AnimationLibrary::DefaultTypeOfBitmap=TYPE_SYSTEM;
					break;
			   default:
				  	AnimationLibrary::DefaultTypeOfBitmap=TYPE_MEMORY;
			   		 break;
	    	}
#else
			AnimationLibrary::DefaultTypeOfBitmap=TYPE_VIDEO;
#endif
        }
		loop=globals->Attribute("loop");
		if(loop==NULL) 
			AnimationLibrary::DefaultLoop=LOOP_START;
		else
			AnimationLibrary::DefaultLoop=GetLoopTypeFromChar(loop);
	}

	AnimationLibraryFrames* aniframes=NULL;
	AnimationLibraryFrame* aniframe=NULL;

	//all animations
	int originx, originy, tilex, tiley;

//graphic items first
	AnimationLibrary::LogEntry("Reading Single Graphics First",false,"animation.log");
	for( nodule= map->FirstChild( "graphic" );
		nodule;
		nodule = nodule->NextSibling( "graphic" ) )
	{
		ok=false;
		node=nodule->ToElement();
		//attributes

		//first get core details
		id=node->Attribute("id");
		if(id==NULL || strcmp("",id)==0)
		{
			AnimationLibrary::LogEntry("Graphic found with no id, aborting",false,"animation.log");
			ok=false;
			break;
		}	
		else
		{
			if(node->QueryIntAttribute("depth",&depth)!=TIXML_SUCCESS) depth=-1;
			if(node->QueryIntAttribute("isasheetgraphic",&isasheetgraphic)!=TIXML_SUCCESS) isasheetgraphic=-1;
			if(node->QueryIntAttribute("ppmask",&hasaPPCOLmask)!=TIXML_SUCCESS) hasaPPCOLmask=-1;
			if(node->QueryIntAttribute("sheetitemwidth",&swidth)!=TIXML_SUCCESS) swidth=-1;
			if(node->QueryIntAttribute("sheetitemheight",&sheight)!=TIXML_SUCCESS) sheight=-1;
			//no equivalent defaults in global section
			if(node->QueryIntAttribute("originx",&originx)!=TIXML_SUCCESS) originx=0;
			if(node->QueryIntAttribute("originy",&originy)!=TIXML_SUCCESS) originy=0;
			if(node->QueryIntAttribute("tilex",&tilex)!=TIXML_SUCCESS) tilex=0;
			if(node->QueryIntAttribute("tiley",&tiley)!=TIXML_SUCCESS) tiley=0;
			if(node->QueryIntAttribute("bmp_type",&bitmaptype)!=TIXML_SUCCESS) bitmaptype=-1;
	
			bmp_file=node->Attribute("bmp_file");
			if(bmp_file==NULL || strcmp("",bmp_file)==0)
			{
				AnimationLibrary::LogEntry("Graphic found with no filename, aborting",false,"animation.log");
				ok=false;
			}
			else
			{
				AnimationLibrary::LogEntry((string)"Adding single bitmap: "+bmp_file,false,"animation.log");
				//create animation but don't add it yet - all frames are part of a master frames item
				//graphics aren't animations so no need for defaults - a graphic is a single graphic animationframes object
				aniframes=new AnimationLibraryFrames(id);
				aniframes->BitmapCreator=BitmapCreator;

				if(hasaPPCOLmask<0) hasaPPCOLmask=AnimationLibrary::DefaultHasPPCOLMask;
				
				aniframe=new AnimationLibraryFrame(aniframes,bmp_file,bitmaptype,0,0,isasheetgraphic,originx,originy,tilex,tiley,swidth,sheight,(hasaPPCOLmask!=0));
				ok=aniframes->AddAnimationFrame(aniframe);
				if(aniframe->Image!=NULL && aniframe->CreatedOk && ok)
				{
					AnimationLibrary::LogEntry("Graphic item success, adding to list",false,"animation.log");
					this->AddAnimation(aniframes);
					ok=true;
				}
				else
				{
					AnimationLibrary::LogEntry("Graphic image item failed, removing and aborting",false,"animation.log");
					delete aniframe;
					ok=false;
				}
			}
			if(!ok)
			{
				AnimationLibrary::LogEntry("Graphic item failed, removing animation object and aborting",false,"animation.log");
				delete aniframes;
			}
			else
			{
				AnimationLibrary::LogEntry("Graphic Animation item success, adding to list",false,"animation.log");
				if (!this->AddAnimation(aniframes))
				{
					ok=false;
				}
			}
		}
		if(!ok) break;
	}

	if(ok)
	{
		AnimationLibrary::LogEntry("finished loading graphics OK",false,"animation.log");


//animations
		AnimationLibrary::LogEntry("Reading Animations",false,"animation.log");
		bmp_file=NULL;
		for( nodule= map->FirstChild( "animation" );
			nodule;
			nodule = nodule->NextSibling( "animation" ) )
		{
			node=nodule->ToElement();
			//attributes

			//first get core details
			id=node->Attribute("id");
			if(id==NULL || strcmp("",id)==0)
			{
				AnimationLibrary::LogEntry("Animation found with no id, aborting",false,"animation.log");
				ok=false;
				break;
			}
			else
			{
				if(node->QueryIntAttribute("depth",&depth)!=TIXML_SUCCESS) depth=-1;
				if(node->QueryIntAttribute("millisecondwait",&ms)!=TIXML_SUCCESS) ms=-1;
				if(node->QueryIntAttribute("ppmask",&hasaPPCOLmask)!=TIXML_SUCCESS) hasaPPCOLmask=-1;
				if(node->QueryIntAttribute("framewait",&fw)!=TIXML_SUCCESS) fw=-1;
				if(node->QueryIntAttribute("automode",&automode)!=TIXML_SUCCESS) automode=-1;
				if(node->QueryIntAttribute("sheetgrid",&sgrid)!=TIXML_SUCCESS) sgrid=-1;
				if(node->QueryIntAttribute("sheetitemwidth",&swidth)!=TIXML_SUCCESS) swidth=-1;
				if(node->QueryIntAttribute("sheetitemheight",&sheight)!=TIXML_SUCCESS) sheight=-1;
				if(node->QueryIntAttribute("isasheetgraphic",&isasheetgraphic)!=TIXML_SUCCESS) isasheetgraphic=-1;
				if(node->QueryIntAttribute("originx",&originx)!=TIXML_SUCCESS) originx=0;
				if(node->QueryIntAttribute("originy",&originy)!=TIXML_SUCCESS) originy=0;
				if(node->QueryIntAttribute("bmp_type",&bitmaptype)!=TIXML_SUCCESS) bitmaptype=-1;
				if(node->QueryIntAttribute("sequencecount",&sequencecount)!=TIXML_SUCCESS) sequencecount=0;
				
				bmp_file=node->Attribute("bmp_file");
				loop=node->Attribute("loop");
				if(loop==NULL) 
					lt=AnimationLibrary::DefaultLoop;
				else
					lt=GetLoopTypeFromChar(loop);

				if(sgrid==-1) sgrid=(int)AnimationLibrary::DefaultSheetGrid;
				//create animation but don't add it yet
				string newfile;
				if(bmp_file==NULL || strcmp("",bmp_file)==0) newfile="";
				else newfile=(string)bmp_file;

				if(hasaPPCOLmask<0) hasaPPCOLmask=AnimationLibrary::DefaultHasPPCOLMask;

				if(automode!=-1)
					aniframes=new AnimationLibraryFrames(id,lt,ms,fw,automode==1?true:false,depth,originx, originy, (sgrid!=0), swidth, sheight,isasheetgraphic,bitmaptype,newfile,hasaPPCOLmask!=0);
				else
					aniframes=new AnimationLibraryFrames(id,lt,ms,fw,this->DefaultAutoMove,depth,originx, originy, (sgrid!=0), swidth, sheight,isasheetgraphic,bitmaptype,newfile,hasaPPCOLmask!=0);

				aniframes->BitmapCreator=BitmapCreator;
				//now get animations frames
				//if using a sequence count then override these
				if(sequencecount>100)
				{
					AnimationLibrary::LogEntry("Sequence count > 100! aborting animation",false,"animation.log");
					ok=false;
				}
				else
				{

					if(sequencecount>0)
					{
						AnimationLibrary::LogEntry("Using sequence count for tiles",false,"animation.log");
						int i;
						for(i=0;i<sequencecount;++i)
						{
							//code copied from below
							if(bmp_file==NULL || strcmp("",bmp_file)==0) bmp_file="";
							aniframe=new AnimationLibraryFrame(aniframes,bmp_file,bitmaptype,ms,fw, 1, originx, originy, i, 0, swidth, sheight,hasaPPCOLmask!=0);
							ok=aniframes->AddAnimationFrame(aniframe);
							if(aniframe->Image!=NULL && aniframe->CreatedOk && ok)
							{
								AnimationLibrary::LogEntry("Animation item success, adding to list",false,"animation.log");
								this->AddAnimation(aniframes);
							}
							else
							{
								ok=false;
								AnimationLibrary::LogEntry("Animation image item failed, aborting",false,"animation.log");
								break;
							}
						}
					}
					else
					{
						int tilex, tiley, sheetitemwidth, sheetitemheight;
						for( innernodule= node->FirstChild( "animationitem" );
							innernodule;
							innernodule = innernodule->NextSibling( "animationitem" ) )
						{
							innernode=innernodule->ToElement();

							bmp_file=innernode->Attribute("bmp_file");
							if((bmp_file==NULL || strcmp("",bmp_file)==0) && aniframes->DefaultFileName=="")
							{
								AnimationLibrary::LogEntry("Animationitem found with no filename, aborting",false,"animation.log");
								ok=false;
								break;
							}
							else
							{
								if(innernode->QueryIntAttribute("millisecondwait",&ms)!=TIXML_SUCCESS) ms=-1;
								if(innernode->QueryIntAttribute("framewait",&fw)!=TIXML_SUCCESS) fw=-1;
								hasaPPCOLmask=aniframes->DefaultHasPPCOLMask;
								if(innernode->QueryIntAttribute("isasheetgraphic",&isasheetgraphic)!=TIXML_SUCCESS) isasheetgraphic=-1;
								if(innernode->QueryIntAttribute("originx",&originx)!=TIXML_SUCCESS) originx=-1;
								if(innernode->QueryIntAttribute("originy",&originy)!=TIXML_SUCCESS) originy=-1;
								if(innernode->QueryIntAttribute("tilex",&tilex)!=TIXML_SUCCESS) tilex=0;
								if(innernode->QueryIntAttribute("tiley",&tiley)!=TIXML_SUCCESS) tiley=0;
								if(innernode->QueryIntAttribute("sheetitemwidth",&sheetitemwidth)!=TIXML_SUCCESS) sheetitemwidth=-1;
								if(innernode->QueryIntAttribute("sheetitemheight",&sheetitemheight)!=TIXML_SUCCESS) sheetitemheight=-1;
								if(innernode->QueryIntAttribute("bmp_type",&bitmaptype)!=TIXML_SUCCESS) bitmaptype=-1;

								//if its a sheet item then check if the master image exists first
								//if it does then continue as normal
								//if it isn't create/load it first so that
								//calling animationlibraryframe constructor cannot fail
								//create frame. frame constructor sorts out file loading, etc.
								if(bmp_file==NULL || strcmp("",bmp_file)==0) bmp_file="";
								aniframe=new AnimationLibraryFrame(aniframes,bmp_file,bitmaptype,ms,fw, isasheetgraphic, originx, originy, tilex, tiley, sheetitemwidth, sheetitemheight,hasaPPCOLmask!=0);
								ok=aniframes->AddAnimationFrame(aniframe);
								if(aniframe->Image!=NULL && aniframe->CreatedOk && ok)
								{
									AnimationLibrary::LogEntry("Animation item success, adding to list",false,"animation.log");
									this->AddAnimation(aniframes);
								}
								else
								{
									ok=false;
									AnimationLibrary::LogEntry("Animation image item failed, aborting",false,"animation.log");
									break;
								}
							}		
						}
					}
				}
				if(!ok)
				{
					AnimationLibrary::LogEntry("Animation item failed, removing it and aborting",false,"animation.log");
					delete aniframes;
				}
				else
				{
					AnimationLibrary::LogEntry("Animation item success, adding to list",false,"animation.log");
					if(!this->AddAnimation(aniframes))
					{
						ok=false;
						delete aniframes;
						break;
					}
				}
			}
			if(!ok) break;
		}
		AnimationLibrary::LogEntry("finished loading animations",false,"animation.log");
	}
	if(!ok)
	{
		AnimationLibrary::LogEntry("ABORTED DUE TO ERRORS AS LISTED",false,"animation.log");
		LoadError=true;
		DestroyAll();
	}
	return ok;
}

LoopType AnimationLibrary::GetLoopTypeFromChar(const char* loop) const
{
	LoopType lt;
	if	   (strcmp("once",loop)==0) lt=LOOP_ONCE;
	else if(strcmp("start",loop)==0) lt=LOOP_START;
	else if(strcmp("reverseonce",loop)==0) lt=LOOP_REVERSEONCE;
	else if(strcmp("reverserepeat",loop)==0) lt=LOOP_REVERSEREPEAT;
	else if(strcmp("reverseback",loop)==0) lt=LOOP_REVERSEBACK;
	else lt=LOOP_START;

	return lt;
}

void AnimationLibrary::DebugData(const std::string& file) const
{
	FILE *stream;
	map<string,AnimationLibraryFrames*>::const_iterator AnimationIterator;
	vector<AnimationLibraryFrame*>::const_iterator AnimationIteratorFrame;
	stream = fopen( file.c_str(), "w+t" );

	if(stream!=NULL)
	{
		fprintf(stream,"GLOBALS (defaults)\n");
		fprintf(stream,"AutoMove: %d, frame wait: %d, millisecond wait: %d, fps: %d",AnimationLibrary::DefaultAutoMove,AnimationLibrary::DefaultFrameWait,AnimationLibrary::DefaultMilliSecondWait,this->fps);
		fprintf(stream,"\nLoop types: LOOP_INVALID=-1, LOOP_START=0,LOOP_REVERSEREPEAT=1,LOOP_REVERSEONCE=2, LOOP_REVERSEBACK=3, LOOP_ONCE=4");
		fprintf(stream,"\nLoop type: %d, depth: %d", AnimationLibrary::DefaultLoop,AnimationLibrary::DefaultColourDepth);
		fprintf(stream,"\n\nANIMATIONS");
		for (AnimationIterator = AnimationFrames.begin(); AnimationIterator!= AnimationFrames.end(); AnimationIterator++)
		{
			fprintf(stream,"\n\nid: %s, default frame wait: %d, default millisec wait: %d, default loop: %d",(AnimationIterator->second)->Id.c_str(),(AnimationIterator->second)->DefaultFrameWait,
						(AnimationIterator->second)->DefaultMilliSecondWait,(AnimationIterator->second)->Loop);
			fprintf(stream,"\n Animation Frames");
		}

		fclose(stream);
	}
}

AXL_BITMAP* AnimationLibrary::GetFirstGraphic(const std::string& id) const
{
	AnimationLibraryFrames* ani;
	ani=this->GetAnimation(id);
	if(!ani) return NULL;
	if(ani->FrameItems.size()<1) 
		return NULL;
	else
		return ani->FrameItems[0]->Image;
}

//function helpers for when you are using the allegro_config routines
void AnimationLibrary::LogEntry(const string& s, bool flag, const string& f)
{
#ifdef axl_concus
	Configuration::LogEntry("normal: "+s,flag,f);
#else
		FILE *stream;
		if(!flag) stream = fopen( f.c_str(), "a+t" );
		else stream = fopen( f.c_str(), "w+t" );

		if(stream!=NULL)
		{
			fprintf(stream,"normal: %s\n",s.c_str());
			fclose(stream);
		}

#endif
	return;

}
void AnimationLibrary::SetGlobalErrorString(const string& s)
{
#ifdef axl_concus
	Configuration::GlobalErrorString=s;
#endif

}
const string AnimationLibrary::GetGlobalErrorString()
{
#ifdef axl_concus
	return Configuration::GlobalErrorString;
#else
	return "";
#endif
}

